<?php
/**
 * Created by PhpStorm
 * User: Jhinwy
 * Date: 4/19/24
 * Time: 5:55 PM
 */

namespace app\common\service\media;

use app\common\model\media\Media;
use app\common\model\media\MediaAccount;
use app\common\model\media\MediaAuth;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use think\facade\Cache;
use think\facade\Log;

class BdService
{
    const REDIS_MEDIA_BD_TOKEN     = 'redis_media_bd_token_';
    const REDIS_MEDIA_BD_REF_TOKEN = 'redis_media_bd_ref_token_';

    protected $config;
    protected $appId;
    protected $platformId;
    protected $secret;


    public function __construct($authId)
    {
        $mediaAuth        = MediaAuth::where('id', $authId)->findOrEmpty();
        $this->config     = config('media.bd') ?? [];
        $this->appId      = $mediaAuth->app_id ?? '';
        $this->platformId = $mediaAuth->platform_id ?? '';
        $this->secret     = $mediaAuth->secret ?? '';
    }


    public function getEmpowerUrl($state = 0)
    {
        $redirect_uri = env('app.host') . $this->config['redirect_uri'];
        return sprintf(
            $this->config['empower_url'] ?? '',
            $this->platformId,
            $this->appId,
            $state,
            urlencode($redirect_uri),
            );
    }


    public function getToken($authCode, $userId)
    {
        try {
            $headers = [
                'Content-Type' => 'application/json',
            ];
            $fields  = [
                'appId'     => $this->appId,
                'secretKey' => $this->secret,
                'authCode'  => $authCode,
                'userId'    => $userId
            ];
            Log::write('请求百度授权Token==>' . json_encode($fields), 'info');
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['token_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            $data     = json_decode($contents, true);
            list($advertiserId, $accessToken, $openId) = $this->cacheToken($data);
            if (!$accessToken) {

                throw new \Exception('无效的Token');
            }

            return [$advertiserId, $accessToken, $openId];
        } catch (\Exception $exception) {
            Log::error('获取百度token失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 缓存token
     *
     * @param $data
     * @return array|bool
     */
    public function cacheToken($data)
    {
        Log::write('缓存百度授权Token==>' . json_encode($data), 'info');
        $data                 = $data['data'] ?? [];
        $accessToken          = $data['accessToken'] ?? '';
        $accessTokenExpiresIn = $data['expiresIn'] ?? '';
        $refToken             = $data['refreshToken'] ?? 0;
        $refTokenIn           = $data['refreshExpiresIn'] ?? 0;
        $advertiserId         = $data['userId'] ?? 0;
        $openId               = $data['openId'] ?? '';

        if (!$accessToken || !$accessTokenExpiresIn || !$refToken || !$refTokenIn) {

            return false;
        }

        // 缓存巨量Token
        Cache::set(self::REDIS_MEDIA_BD_TOKEN . $advertiserId, $accessToken, $accessTokenExpiresIn);
        Cache::set(self::REDIS_MEDIA_BD_REF_TOKEN . $advertiserId, $refToken, $refTokenIn);

        return [$advertiserId, $accessToken, $openId];
    }


    /**
     * 获取缓存token
     *
     * @return bool|mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getCacheToken($advertiserId)
    {
        if ($accessToken = Cache::get(self::REDIS_MEDIA_BD_TOKEN . $advertiserId)) {

            return $accessToken;
        }
        // token过期刷新快手token
        if ($refToken = Cache::get(self::REDIS_MEDIA_BD_REF_TOKEN . $advertiserId)) {
            if ($accessToken = $this->refToken($refToken, $advertiserId)) {

                return $accessToken;
            }
        }

        return false;
    }


    /**
     * 刷新快手token
     *
     * @param $refToken
     * @return bool
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function refToken($refToken, $userId)
    {
        try {
            $headers  = [
                'Content-Type' => 'application/json',
            ];
            $fields   = [
                'appId'        => $this->appId,
                'secretKey'    => $this->secret,
                'refreshToken' => $refToken,
                'userId'       => $userId
            ];
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['ref_token_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            $data     = json_decode($contents, true);
            list($advertiserId, $accessToken, $openId) = $this->cacheToken($data);
            if (!$accessToken) {

                throw new \Exception('无效的Token');
            }

            return $accessToken;
        } catch (\Exception $exception) {
            Log::error('刷新百度token失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 获取百度管家信息
     *
     * @param $openId
     * @param $accessToken
     * @param $userId
     * @return array|bool|mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getUserInfo($openId, $accessToken, $userId)
    {
        try {
            $headers  = [
                'Content-Type' => 'application/json',
            ];
            $fields   = [
                'openId'      => $openId,
                'accessToken' => $accessToken,
                'userId'      => $userId
            ];
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['user_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            Log::info('【百度管家信息】' . $contents);
            $data = json_decode($contents, true);
            if (!$data = $data['data'] ?? []) {
                throw new \Exception('管家信息不存在');
            }

            return $data;
        } catch (\Exception $exception) {
            Log::error('获取百度管家失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 获取广告主
     *
     * @param $advertiserId
     * @param $token
     * @param $userName
     * @return bool|int
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getAdvertiser($authId, $advertiserId, $token, $userName)
    {
        try {
            $headers  = [
                'Content-Type' => 'application/json',
            ];
            $fields   = [
                'header' => [
                    'accessToken' => $token,
                    'userName'    => $userName
                ],
                'body'   => [
                    'mccid' => null, // 不传该字段会报错
                ]
            ];
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['advertiser_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            Log::info('【百度广告主信息】' . $contents);
            $data = json_decode($contents, true);
            if (!$data = $data['body']['data'] ?? []) {
                throw new \Exception('广告主信息不存在');
            }

            $insertData = [];
            foreach ($data as $item) {
                if (MediaAccount::where('advertiser_id', $item['userid'] ?? 0)->where('media_id', Media::SOURCE_BD)->findOrEmpty()->isEmpty()) {
                    $insertData[] = [
                        'media_auth_id'      => $authId,
                        'auth_advertiser_id' => $advertiserId,
                        'advertiser_id'      => $item['userid'] ?? 0,
                        'advertiser_name'    => $item['username'] ?? '',
                        'company'            => '',
                        'admin_id'           => 0,
                        'media_id'           => Media::SOURCE_BD,
                        'create_time'        => time(),
                        'update_time'        => time()
                    ];
                }
            }

            return MediaAccount::insertAll($insertData);
        } catch (\Exception $exception) {
            Log::error('获取百度授权广告主失败：' . $exception->getMessage());

            return false;
        }
    }


    /**
     * 获取广告主成本
     *
     * @param $authId
     * @param $advertiserId
     * @param $advertiserName
     * @param $linkId
     * @param $date
     * @return int|mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getAdvertiserReport($authId, $advertiserId, $advertiserName, $date)
    {
        if (!$token = $this->getCacheToken($authId)) {
            Log::error('获取百度token失败：' . $advertiserId . $advertiserName);

            return 0;
        }

        try {
            $headers  = [
                'Content-Type' => 'application/json',
            ];
            $fields   = [
                'header' => [
                    'accessToken' => $token,
                    'userName'    => $advertiserName
                ],
                'body'   => [
                    "reportType" => 2330652,  // 信息流推广报告
                    "startDate"  => $date,
                    "endDate"    => $date,
                    "timeUnit"   => "DAY",
                    "columns"    => ["date", "userName", "impression", "click", "cost", "ctr", "cpc"],
                    "sorts"      => [],
                    "filters"    => [],
                    "startRow"   => 0,
                    "rowCount"   => 200,
                    "needSum"    => false,  // 是否需要汇总
                    "userIds"    => [$advertiserId]
                ]
            ];
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['report_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            Log::info('【百度成本报告信息】' . $contents);
            $data = json_decode($contents, true);
            if (!$data = $data['body']['data'][0]['rows'] ?? []) {

                return 0;
            }
            $costData = $data[0] ?? [];
            if ($costData) {

                return $costData['cost'] ?? 0;
            }

            return 0;
        } catch (\Exception $exception) {
            Log::error('获取百度授权广告主失败：' . $exception->getMessage());

            return 0;
        }
    }


    /**
     * 获取百度素材视频报告
     *
     * @param $authId
     * @param $advertiserId
     * @param $advertiserName
     * @param $date
     * @return array|int
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function getVideoReport($authId, $advertiserId, $advertiserName, $date)
    {
        if (!$token = $this->getCacheToken($authId)) {
            Log::error('获取百度token失败：' . $advertiserId . $advertiserName);

            return [];
        }

        try {
            $headers  = [
                'Content-Type' => 'application/json',
            ];
            $fields   = [
                'header' => [
                    'accessToken' => $token,
                    'userName'    => $advertiserName
                ],
                'body'   => [
                    "reportType" => 114718,  // 视频报告
                    "startDate"  => $date,
                    "endDate"    => $date,
                    "timeUnit"   => "DAY",
                    "startRow"   => 0,
                    "rowCount"   => 200,
                    "userIds"    => [$advertiserId]
                ]
            ];
            $client   = new Client();
            $response = $client->request(
                'POST',
                $this->config['report_api'] ?? '',
                [
                    'headers'            => $headers,
                    'timeout'            => 60,
                    RequestOptions::JSON => $fields
                ]
            );
            if ($response->getStatusCode() !== 200) {
                throw new \Exception('请求失败');
            }
            $contents = $response->getBody()->getContents();
            Log::info('【百度视频报告信息】' . $contents);
            $data = json_decode($contents, true);
            if (!$data = $data['body']['data'][0]['rows'] ?? []) {

                return 0;
            }
            $result = [];
            foreach ($data as $item) {
                array_push($result, [
                    'charge'           => $item['cost'] ?? 0,
                    'package_name'     => $item['videoNameStatus'] ?? '',
                    'cover_image_urls' => $item['videoInfo']['videoThumbnail'] ?? '',
                    'video_urls'       => $item['videoInfo']['videoURL'] ?? '',
                    'photo_click'      => $item['click'] ?? 0,
                    'play_3s_ratio'    => $item['playCount1'] ?? 0,
                    'show'             => $item['impression'] ?? 0,
                ]);
            }

            return $result;
        } catch (\Exception $exception) {
            Log::error('获取百度视频报告信息失败：' . $exception->getMessage());

            return [];
        }
    }
}
